//
//  ZYDraggableView.swift
//  ZYUICommon
//
//  Created by Yi Zhou on 2025/1/11.
//

import Foundation
import UIKit

/// 支持拖拽和缩放的view
open class ZYDraggableView: UIView {
    
    /// 希望使用哪种手势
    public var gestureType: ZYEnumDraggableGestureType = .both {
        didSet {
            switch gestureType {
            case .pan:
                self.removeGestureRecognizer(pinchGesture)
            case .pin:
                self.removeGestureRecognizer(panGesture)
            case .both:
                break
            }
        }
    }
    
    /// 最小缩放比例
    public var minimumScale: CGFloat = 0.5
    
    /// 最大缩放比例
    public var maximumScale: CGFloat = 2.0
    
    /// 拖拽时触边回弹的间距
    public var bounceDistance: CGFloat = 10
    
    /// 拖拽手势
    private lazy var panGesture: UIPanGestureRecognizer = {
        return UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
    }()
    
    /// 缩放手势
    private lazy var pinchGesture: UIPinchGestureRecognizer = {
        return UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(_:)))
    }()
    
    public override init(frame: CGRect) {
        super.init(frame: frame)
        self.addGestureRecognizer(panGesture)
        self.addGestureRecognizer(pinchGesture)
    }
    
    required public init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

extension ZYDraggableView {
    
    @objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
        let translation = gesture.translation(in: self.superview)
        var newCenter = CGPoint(x: self.center.x + translation.x, y: self.center.y + translation.y)
        
        if let superview = self.superview {
            let bounds = superview.bounds
            
            // 左边和右边的边界处理
            if newCenter.x < self.frame.width / 2 {
                newCenter.x = self.frame.width / 2
                animateBounceBack(for: .left, in: superview)
            } else if newCenter.x > bounds.width - self.frame.width / 2 {
                newCenter.x = bounds.width - self.frame.width / 2
                animateBounceBack(for: .right, in: superview)
            }
            
            // 上边和下边的边界处理
            if newCenter.y < self.frame.height / 2 {
                newCenter.y = self.frame.height / 2
                animateBounceBack(for: .top, in: superview)
            } else if newCenter.y > bounds.height - self.frame.height / 2 {
                newCenter.y = bounds.height - self.frame.height / 2
                animateBounceBack(for: .bottom, in: superview)
            }
        }
        
        self.center = newCenter
        gesture.setTranslation(.zero, in: self.superview)
    }
    
    @objc private func handlePinch(_ gesture: UIPinchGestureRecognizer) {
        // 如果手势状态是结束了，我们检查是否需要回弹
        if gesture.state == .ended {
            let currentScale = self.transform.a
            
            if currentScale <= minimumScale + 0.1 || currentScale >= maximumScale - 0.1 {
                animateScaleBackToLimits(currentScale: currentScale, minimumScale: minimumScale, maximumScale: maximumScale)
            }
            return
        }
        
        // 计算新的缩放比例
        var newScale = self.transform.a * gesture.scale
        
        // 确保新的缩放比例在规定的范围内
        if newScale < minimumScale {
            newScale = minimumScale
        } else if newScale > maximumScale {
            newScale = maximumScale
        }
        
        // 应用新的缩放比例
        self.transform = CGAffineTransform(scaleX: newScale, y: newScale)
        
        // 重置手势的累计缩放比例
        gesture.scale = 1.0
    }
    
}


extension ZYDraggableView {
    // 回弹动画方法
    private func animateBounceBack(for direction: ZYEnumDirection, in superview: UIView) {
        let duration: TimeInterval = 0.2
        let springDamping: CGFloat = 0.5
        
        switch direction {
        case .left:
            UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: springDamping, initialSpringVelocity: 1, options: [.curveEaseInOut], animations: {
                self.center.x -= self.bounceDistance
            }) { _ in
                UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: springDamping, initialSpringVelocity: 1, options: [.curveEaseInOut], animations: {
                    self.center.x += self.bounceDistance
                })
            }
        case .right:
            UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: springDamping, initialSpringVelocity: 1, options: [.curveEaseInOut], animations: {
                self.center.x += self.bounceDistance
            }) { _ in
                UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: springDamping, initialSpringVelocity: 1, options: [.curveEaseInOut], animations: {
                    self.center.x -= self.bounceDistance
                })
            }
        case .top:
            UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: springDamping, initialSpringVelocity: 1, options: [.curveEaseInOut], animations: {
                self.center.y -= self.bounceDistance
            }) { _ in
                UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: springDamping, initialSpringVelocity: 1, options: [.curveEaseInOut], animations: {
                    self.center.y += self.bounceDistance
                })
            }
        case .bottom:
            UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: springDamping, initialSpringVelocity: 1, options: [.curveEaseInOut], animations: {
                self.center.y += self.bounceDistance
            }) { _ in
                UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: springDamping, initialSpringVelocity: 1, options: [.curveEaseInOut], animations: {
                    self.center.y -= self.bounceDistance
                })
            }
        }
    }
    
    private func animateScaleBackToLimits(currentScale: CGFloat, minimumScale: CGFloat, maximumScale: CGFloat) {
        let duration: TimeInterval = 0.3
        let springDamping: CGFloat = 0.7
        
        UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: springDamping, initialSpringVelocity: 1, options: [.curveEaseInOut], animations: {
            if currentScale <= minimumScale + 0.1 {
                self.transform = CGAffineTransform(scaleX: minimumScale, y: minimumScale)
            } else if currentScale >= maximumScale - 0.1 {
                self.transform = CGAffineTransform(scaleX: maximumScale, y: maximumScale)
            }
        })
    }
}
